#!/usr/bin/env python
# SpringDS v1.0 Beta 1 - a (cross-platform?) wrapper for the FRC Driver Station
# Copyright (C) 2012 River Hill HS Robotics Team (Albert H.)
# 
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
# 
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
# 
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
# 
# This is the SpringDS Panel, a lighter and (probably) more useful version
# of SpringDS. It allows complete, single-click control of the network settings,
# great for coding work... and of course, launching the driver station.
# 
# -*- coding: iso-8859-15 -*-
# generated by wxGlade 0.6.5 (standalone edition) on Sun Mar 25 19:43:09 2012

import wx
import os, sys
import traceback
import pyNM
import threading
import time
import subprocess
import psutil

import SpringDSCrash
import SpringDSConfig

#import random

if sys.platform == 'win32':
    import win32api

# Variables

# Version
SPRINGDS_VERSION = "1.0 beta 1"

# Functions

# MsgBox - shows a message box.
# Types: wx.ICON_INFORMATION, wx.ICON_EXCLAMATION, wx.ICON_ERROR, wx.ICON_ERROR
def MsgBox(text, title, type, parent=None):
    dlg = wx.MessageDialog(parent, text, title, 
            wx.OK | type)
    dlg.ShowModal()

def ErrorBox(traceback):
    SDSCrashFrameInstance = SpringDSCrash.SDSCrashFrame(traceback)
    #app.SetTopWindow(SDSCrashFrameInstance)
    SDSCrashFrameInstance.MakeModal()
    SDSCrashFrameInstance.ShowModal()
    SDSCrashFrameInstance.MakeModal(False)
    
# Define notification event for thread completion updates
EVT_UPDATE_STATUS_ID = wx.NewId()
# Define notification event for window termination trigger
EVT_TERMINATE_WINDOW_ID = wx.NewId()
# Define notification event for thread progress updates
EVT_UPDATE_PROGRESS_ID = wx.NewId()
# Define notification event for showing an error box
EVT_ERROR_NOTIFY_ID = wx.NewId()
# Define notification event for turning the button back to normal
EVT_RESET_LAUNCHER_BTN_ID = wx.NewId()

def EVT_UPDATE_STATUS(win, func):
    """Define Result Event."""
    win.Connect(-1, -1, EVT_UPDATE_STATUS_ID, func)

def EVT_TERMINATE_WINDOW(win, func):
    """Define Result Event."""
    win.Connect(-1, -1, EVT_TERMINATE_WINDOW_ID, func)

def EVT_UPDATE_PROGRESS(win, func):
    """Define Result Event."""
    win.Connect(-1, -1, EVT_UPDATE_PROGRESS_ID, func)

def EVT_ERROR_NOTIFY(win, func):
    """Define Result Event."""
    win.Connect(-1, -1, EVT_ERROR_NOTIFY_ID, func)

def EVT_RESET_LAUNCHER_BTN(win, func):
    """Define Result Event."""
    win.Connect(-1, -1, EVT_RESET_LAUNCHER_BTN_ID, func)
    
class IOStatusParser:
    def __init__(self, updatewin, oldio):
        self.updatewin = updatewin
        self.oldio = oldio
    def write(self, text):
        if text.strip() != "":
            partn = 0
            finaltext = ""
            for part in text.strip().split(" "):
                partn += 1
                if part != "":
                    if (part[0] == '[') and (part[-1] == ']'):
                        # Check
                        if (partn == 2) and (part == "[SpringDSFrame.on_paint]"):
                            finaltext = ""
                            break
                    else:
                        finaltext = " ".join(text.strip().split(" ")[partn-1:])
                        break
            wx.PostEvent(self.updatewin, UpdateStatusEvent(finaltext))
        self.oldio.write(text)
    '''def close(self):
        self.logfile.write(" Log Session End - "+date("%Y-%m-%d %H:%M:%S")+" **\n")
        self.logfile.close()'''
class UpdateStatusEvent(wx.PyEvent):
    """Event that carries the status update data."""
    def __init__(self, data):
        """Init Result Event."""
        wx.PyEvent.__init__(self)
        self.SetEventType(EVT_UPDATE_STATUS_ID)
        self.data = data

class TerminateWindowEvent(wx.PyEvent):
    """Event that tells the window thread to exit."""
    def __init__(self, data):
        """Init Result Event."""
        wx.PyEvent.__init__(self)
        self.SetEventType(EVT_TERMINATE_WINDOW_ID)
        self.data = data

class UpdateProgressEvent(wx.PyEvent):
    """Event that carries the progress update data."""
    def __init__(self, data):
        """Init Result Event."""
        wx.PyEvent.__init__(self)
        self.SetEventType(EVT_UPDATE_PROGRESS_ID)
        self.data = data

class ErrorNotifyEvent(wx.PyEvent):
    """Event that tells the window something bad happened."""
    def __init__(self, data):
        """Init Result Event."""
        wx.PyEvent.__init__(self)
        self.SetEventType(EVT_ERROR_NOTIFY_ID)
        self.data = data

class ResetLauncherBtnEvent(wx.PyEvent):
    """Event that tells the window something bad happened."""
    def __init__(self, data):
        """Init Result Event."""
        wx.PyEvent.__init__(self)
        self.SetEventType(EVT_RESET_LAUNCHER_BTN_ID)
        self.data = data
# This is the slave daemon - to prevent GUI lockups when we do network-y stuff,
# we send commands to this daemon, and the daemon sends signals to the GUI in response
# to update progress.
class SpringDS_NM_Slave(threading.Thread):
    def __init__(self, updatewin):
        threading.Thread.__init__(self)
        self.updatewin = updatewin
        self.stopNow = False
        self.oldstdout = sys.stdout
        self.pyNMHandle = None
        self.errBoxOpen = True
        self.action = ""
        self.curAction = ""
        self.networkInFRCMode = False
        self.pyNMInited = False
        self.actionRan = False
    def killSlave(self):
        # Terminate this thread
        self.stopNow = True
    def checkKill(self):
        # Check for flag
        if self.stopNow == True:
            self.doKill()
    def checkActionDiff(self):
        # Check to see if the GUI requested something different, and break if needed!
        if self.action != self.curAction:
            return True
        # Optimization: keep it outside of if loop instead of putting it into the
        # else clause - exercise for the reader as to why this works, and is faster.
        return False
    def initPyNM(self):
        if self.pyNMInited == False:
            wx.PostEvent(self.updatewin, UpdateProgressEvent(5))
            print "[SpringDSPanel] Loading pyNetworkManager..."
            self.pyNMHandle = pyNM.pyNM()
            self.checkKill()
            print "[SpringDSPanel] Using pyNetworkManager version "+str(self.pyNMHandle.getVersion())
            print "[SpringDSPanel] Initializing pyNetworkManager..."
            wx.PostEvent(self.updatewin, UpdateProgressEvent(10))
            self.pyNMHandle.initNM()
            self.checkKill()
            self.pyNMInited = True
    def setAction(self, cmd):
        self.action = cmd
        if cmd == "TerminateDS":
            for proc in psutil.process_iter():
                if sys.platform == 'win32':
                    if proc.name == "Driver Station.exe":
                        proc.terminate()
                self.checkKill()
    def setErrBoxClose(self):
        self.errBoxOpen = False
    def doKill(self):
        # Shut down pyNM
        wx.PostEvent(self.updatewin, UpdateProgressEvent(33))
        print "[SpringDSPanel] Terminating SpringDS and the Driver Station..."
        for proc in psutil.process_iter():
            if sys.platform == 'win32':
                if proc.name == "Dashboard.exe":
                    proc.terminate()
                if proc.name == "Driver Station.exe":
                    proc.terminate()
        wx.PostEvent(self.updatewin, ResetLauncherBtnEvent(None))
        #print "[SpringDSPanel] Pausing for 3 seconds..."
        time.sleep(1)
        try:
            if self.pyNMHandle != None:
                if SpringDSConfig.getCfgNICType() == "wireless":
                    print "[SpringDSPanel] Resetting wireless NIC to DHCP..."
                    self.pyNMHandle.setWirelessDHCP()
                elif SpringDSConfig.getCfgNICType() == "lan":
                    print "[SpringDSPanel] Resetting LAN NIC to DHCP..."
                    self.pyNMHandle.setLANDHCP()
        except:
            # Allow termination
            pass
        wx.PostEvent(self.updatewin, UpdateProgressEvent(66))
        wx.PostEvent(self.updatewin, UpdateProgressEvent(99))
        print "[SpringDSPanel] Restoring I/O..."
        print "[SpringDSPanel] Exiting..."
        time.sleep(1.5)
        sys.stdout = self.oldstdout
        wx.PostEvent(self.updatewin, TerminateWindowEvent(None))
        exit()
    def run(self):
        # Hook the output to our little I/O class so we can catch and interpret it!
        out2status = IOStatusParser(self.updatewin, sys.stdout)
        sys.stdout = out2status
        self.checkKill()
        wx.PostEvent(self.updatewin, UpdateProgressEvent(50))
        try:
            SpringDSConfig.initConfig()
            print "[SpringDSPanel] Ready."
            wx.PostEvent(self.updatewin, UpdateProgressEvent(0))
        except:
            MsgBox("Couldn't load SpringDS configuration!", "Error - SpringDS", wx.ICON_ERROR)
            import traceback
            wx.PostEvent(self.updatewin, ErrorNotifyEvent("".join(traceback.format_exc())))
            while self.errBoxOpen:
                time.sleep(1)
            wx.PostEvent(self.updatewin, TerminateWindowEvent(None))
            exit()
        
        # Now we place this into a while loop to process actions.
        while self.stopNow == False:
            #print "DEBUG: Loop outside"
            self.checkKill()
            self.curAction = self.action
            while 1:
                time.sleep(0.1)
                self.checkKill()
                if self.checkActionDiff():
                    break
                
                if self.actionRan == False:
                    if self.action == "LaunchDS":
                        # Wrap all of this in a try/catch so that we can watch for errors and handle
                        # them nicely!
                        try:
                            wx.PostEvent(self.updatewin, UpdateProgressEvent(1))
                            self.initPyNM()
                            self.checkKill()
                            if self.checkActionDiff():
                                break
                            
                            if SpringDSConfig.getCfgNICType() == "wireless":
                                print "[SpringDSPanel] Setting required FRC static IP and subnet for wireless NIC: "+SpringDSConfig.getCfgStaticIP()+" and "+SpringDSConfig.getCfgSubnet()
                                self.pyNMHandle.setWirelessStaticIPAndSubnet(SpringDSConfig.getCfgStaticIP(), SpringDSConfig.getCfgSubnet())
                            elif SpringDSConfig.getCfgNICType() == "lan":
                                print "[SpringDSPanel] Setting required FRC static IP and subnet for LAN NIC: "+SpringDSConfig.getCfgStaticIP()+" and "+SpringDSConfig.getCfgSubnet()
                                self.pyNMHandle.setLANStaticIPAndSubnet(SpringDSConfig.getCfgStaticIP(), SpringDSConfig.getCfgSubnet())

                            wx.PostEvent(self.updatewin, UpdateProgressEvent(70))
                            self.checkKill()
                            if self.checkActionDiff():
                                break
                            
                            # Now launch the Driver Station (and wait)!
                            print "[SpringDSPanel] Launching FRC Driver Station..."
                            wx.PostEvent(self.updatewin, UpdateProgressEvent(100))
                            subprocess.call(SpringDSConfig.getCfgDriverStationPath())
                            self.checkKill()
                            if self.checkActionDiff():
                                break
                            
                            print "[SpringDSPanel] Ensuring that everything has closed (and if not, terminating them)..."
                            wx.PostEvent(self.updatewin, UpdateProgressEvent(70))
                            for proc in psutil.process_iter():
                                if sys.platform == 'win32':
                                    if proc.name == "Dashboard.exe":
                                        proc.terminate()
                                self.checkKill()
                            self.checkKill()
                            wx.PostEvent(self.updatewin, UpdateProgressEvent(20))
                            
                            if SpringDSConfig.getCfgNICType() == "wireless":
                                print "[SpringDSPanel] Resetting wireless NIC to DHCP..."
                                self.pyNMHandle.setWirelessDHCP()
                            elif SpringDSConfig.getCfgNICType() == "lan":
                                print "[SpringDSPanel] Resetting LAN NIC to DHCP..."
                                self.pyNMHandle.setLANDHCP()
                            self.checkKill()
                            wx.PostEvent(self.updatewin, UpdateProgressEvent(0))
                            wx.PostEvent(self.updatewin, ResetLauncherBtnEvent(None))
                            print "[SpringDSPanel] Ready."
                        except pyNM.pyNMError, err:
                            # TODO: add more cases
                            # Is this a permission error?
                            if err.IsSystemError:
                                # Is this a permission error? (This is a subset of the system error)
                                if err.IsPermissionError:
                                    # Are we on Windows?
                                    if sys.platform == 'win32':
                                        wx.PostEvent(self.updatewin, UnhookOnQuitEvent(None))
                                        # Check args - this should be fixed later to actually check for elevation.
                                        ELEVATED = 0
                                        if len(sys.argv) > 1:
                                            if sys.argv[1] == '--FLAG-SPRINGDS-INTERNAL-ELEVATION-LAUNCH':
                                                # We tried elevating, it failed.
                                                ELEVATED = 1
                                                MsgBox("Could not set network config, even with elevation!", "Error - SpringDS", wx.ICON_ERROR)
                                                self.doKill()
                                                #wx.PostEvent(self.updatewin, TerminateWindowEvent(None))
                                                #print "[SpringDSPanel] Could not set network config, even with elevation. Press ALT-F4 to exit."
                                        try:
                                            if ELEVATED == 0:
                                                #print "DEBUG: sys.argv is "+str(sys.argv)
                                                #print "DEBUG: __file__ is "+str(__file__)
                                                if getattr(sys, 'frozen', False):
                                                    print "[SpringDSPanel] Detected regular old script execution, so re-executing accordingly with elevation."
                                                    #print "DEBUG: executing this:"
                                                    print "'"+sys.executable+" "+" ".join(sys.argv[1:])+"'"
                                                    win32api.ShellExecute(0, "runas", sys.executable, "'"+" ".join(sys.argv[1:])+"' --FLAG-SPRINGDS-INTERNAL-ELEVATION-LAUNCH", None, 1)
                                                    time.sleep(3)
                                                    wx.PostEvent(self.updatewin, TerminateWindowEvent(None))
                                                elif sys.argv[0][len(sys.argv[0])-3:] == '.py':
                                                    print "[SpringDSPanel] Detected regular old script execution (2), so re-executing accordingly with elevation."
                                                    #print "DEBUG: executing this:"
                                                    print "'"+sys.executable+" '"+os.path.abspath(__file__)+"''"
                                                    win32api.ShellExecute(0, "runas", sys.executable, '"'+os.path.abspath(__file__)+'"'+" --FLAG-SPRINGDS-INTERNAL-ELEVATION-LAUNCH", None, 1)
                                                    time.sleep(3)
                                                    wx.PostEvent(self.updatewin, TerminateWindowEvent(None))
                                                elif __file__:
                                                    print "[SpringDSPanel] Detected that we're in a EXE, so executing accordingly with elevation."
                                                    print "'"+__file__+" "+" '".join(sys.argv[1:])+"''"
                                                    win32api.ShellExecute(0, "runas", __file__, "' ".join(sys.argv[1:])+"' --FLAG-SPRINGDS-INTERNAL-ELEVATION-LAUNCH", None, 1)
                                                    time.sleep(3)
                                                    wx.PostEvent(self.updatewin, TerminateWindowEvent(None))
                                                else:
                                                    MsgBox("Failed to determine script execution environment!", "Error - SpringDS", wx.ICON_ERROR)
                                                    self.doKill()
                                                    #wx.PostEvent(self.updatewin, TerminateWindowEvent(None))
                                                    #print "[SpringDSPanel] Failed to determine script execution environment! Press ALT-F4 to exit."
                                                    
                                        except:
                                            MsgBox("Couldn't launch SpringDS in elevated mode!", "Error - SpringDS", wx.ICON_ERROR)
                                            self.doKill()
                                            #wx.PostEvent(self.updatewin, TerminateWindowEvent(None))
                                            #print "[SpringDSPanel] Couldn't launch SpringDS in elevated mode! Press ALT-F4 to exit."
                            else:
                                import traceback
                                if err.exception != "":
                                    wx.PostEvent(self.updatewin, ErrorNotifyEvent(err.exception+"\n\n"+"".join(traceback.format_exc())))
                                else:
                                    wx.PostEvent(self.updatewin, ErrorNotifyEvent("".join(traceback.format_exc())))
                                while self.errBoxOpen:
                                    time.sleep(1)
                                self.doKill()
                                #wx.PostEvent(self.updatewin, TerminateWindowEvent(None))
                                #print "[SpringDSPanel] Code failed! Press ALT-F4 to exit. [Inner loop]"
                                #wx.PostEvent(self.updatewin, UnhookOnQuitEvent(None))
                                raise
                        except SystemExit:
                            pass
                        except:
                            import traceback
                            print "GAHAHHHHHHHHH FAILURE!!!!"
                            traceback.print_exc()
                            wx.PostEvent(self.updatewin, ErrorNotifyEvent("".join(traceback.format_exc())))
                            while self.errBoxOpen:
                                time.sleep(1)
                            self.doKill()
                            #wx.PostEvent(self.updatewin, TerminateWindowEvent(None))
                            #print "[SpringDSPanel] Code failed! Press ALT-F4 to exit."
                            #wx.PostEvent(self.updatewin, UnhookOnQuitEvent(None))
                            raise
                    elif self.action == "TerminateDS":
                        # Wrap all of this in a try/catch so that we can watch for errors and handle
                        # them nicely!
                        try:
                            wx.PostEvent(self.updatewin, UpdateProgressEvent(1))
                            self.initPyNM()
                            self.checkKill()
                            if self.checkActionDiff():
                                break
                            wx.PostEvent(self.updatewin, UpdateProgressEvent(50))
                            print "[SpringDSPanel] Ensuring that everything has closed (and if not, terminating them)..."
                            for proc in psutil.process_iter():
                                if sys.platform == 'win32':
                                    if proc.name == "Dashboard.exe":
                                        proc.terminate()
                                self.checkKill()
                            self.checkKill()
                            wx.PostEvent(self.updatewin, UpdateProgressEvent(70))
                            if SpringDSConfig.getCfgNICType() == 'wireless':
                                print "[SpringDSPanel] Resetting wireless NIC to DHCP..."
                                self.pyNMHandle.setWirelessDHCP()
                            elif SpringDSConfig.getCfgNICType() == 'lan':
                                print "[SpringDSPanel] Resetting LAN NIC to DHCP..."
                                self.pyNMHandle.setLANDHCP()
                            self.checkKill()
                            wx.PostEvent(self.updatewin, UpdateProgressEvent(0))
                            wx.PostEvent(self.updatewin, ResetLauncherBtnEvent(None))
                            print "[SpringDSPanel] Ready."
                        # Note that we don't handle pyNMError as closely as LaunchDS - if the NM
                        # failed because of permission issues, it should've died trying to start.
                        except pyNM.pyNMError, err:
                            # TODO: add more cases
                            # Is this a permission error?
                            import traceback
                            if err.exception != "":
                                wx.PostEvent(self.updatewin, ErrorNotifyEvent(err.exception+"\n\n"+"".join(traceback.format_exc())))
                            else:
                                wx.PostEvent(self.updatewin, ErrorNotifyEvent("".join(traceback.format_exc())))
                            while self.errBoxOpen:
                                time.sleep(1)
                            self.doKill()
                            #wx.PostEvent(self.updatewin, TerminateWindowEvent(None))
                            #print "[SpringDSPanel] Code failed! Press ALT-F4 to exit. [Inner loop]"
                            #wx.PostEvent(self.updatewin, UnhookOnQuitEvent(None))
                            raise
                        except SystemExit:
                            pass
                        except:
                            import traceback
                            print "GAHAHHHHHHHHH FAILURE!!!!"
                            traceback.print_exc()
                            wx.PostEvent(self.updatewin, ErrorNotifyEvent("".join(traceback.format_exc())))
                            while self.errBoxOpen:
                                time.sleep(1)
                            self.doKill()
                            #wx.PostEvent(self.updatewin, TerminateWindowEvent(None))
                            #print "[SpringDSPanel] Code failed! Press ALT-F4 to exit."
                            #wx.PostEvent(self.updatewin, UnhookOnQuitEvent(None))
                            raise
                    elif self.action == "SetupNetwork":
                        # Wrap all of this in a try/catch so that we can watch for errors and handle
                        # them nicely!
                        try:
                            wx.PostEvent(self.updatewin, UpdateProgressEvent(1))
                            self.initPyNM()
                            self.checkKill()
                            if self.checkActionDiff():
                                break
                            
                            wx.PostEvent(self.updatewin, UpdateProgressEvent(50))
                            if SpringDSConfig.getCfgNICType() == "wireless":
                                print "[SpringDSPanel] Setting the FRC static IP and subnet on wireless NIC: "+SpringDSConfig.getCfgStaticIP()+" and "+SpringDSConfig.getCfgSubnet()
                                self.pyNMHandle.setWirelessStaticIPAndSubnet(SpringDSConfig.getCfgStaticIP(), SpringDSConfig.getCfgSubnet())
                            elif SpringDSConfig.getCfgNICType() == "lan":
                                print "[SpringDSPanel] Setting the FRC static IP and subnet on LAN NIC: "+SpringDSConfig.getCfgStaticIP()+" and "+SpringDSConfig.getCfgSubnet()
                                self.pyNMHandle.setLANStaticIPAndSubnet(SpringDSConfig.getCfgStaticIP(), SpringDSConfig.getCfgSubnet())
                            
                            self.checkKill()
                            if self.checkActionDiff():
                                break
                            
                            self.checkKill()
                            wx.PostEvent(self.updatewin, UpdateProgressEvent(0))
                            print "[SpringDSPanel] Ready."
                        except pyNM.pyNMError, err:
                            # TODO: add more cases
                            # Is this a permission error?
                            if err.IsSystemError:
                                # Is this a permission error? (This is a subset of the system error)
                                if err.IsPermissionError:
                                    # Are we on Windows?
                                    if sys.platform == 'win32':
                                        wx.PostEvent(self.updatewin, UnhookOnQuitEvent(None))
                                        # Check args - this should be fixed later to actually check for elevation.
                                        ELEVATED = 0
                                        if len(sys.argv) > 1:
                                            if sys.argv[1] == '--FLAG-SPRINGDS-INTERNAL-ELEVATION-LAUNCH':
                                                # We tried elevating, it failed.
                                                ELEVATED = 1
                                                MsgBox("Could not set network config, even with elevation!", "Error - SpringDS", wx.ICON_ERROR)
                                                self.doKill()
                                                #wx.PostEvent(self.updatewin, TerminateWindowEvent(None))
                                                #print "[SpringDSPanel] Could not set network config, even with elevation. Press ALT-F4 to exit."
                                        try:
                                            if ELEVATED == 0:
                                                #print "DEBUG: sys.argv is "+str(sys.argv)
                                                #print "DEBUG: __file__ is "+str(__file__)
                                                if getattr(sys, 'frozen', False):
                                                    print "[SpringDSPanel] Detected regular old script execution, so re-executing accordingly with elevation."
                                                    #print "DEBUG: executing this:"
                                                    print "'"+sys.executable+" "+" ".join(sys.argv[1:])+"'"
                                                    win32api.ShellExecute(0, "runas", sys.executable, "'"+" ".join(sys.argv[1:])+"' --FLAG-SPRINGDS-INTERNAL-ELEVATION-LAUNCH", None, 1)
                                                    time.sleep(3)
                                                    wx.PostEvent(self.updatewin, TerminateWindowEvent(None))
                                                elif sys.argv[0][len(sys.argv[0])-3:] == '.py':
                                                    print "[SpringDSPanel] Detected regular old script execution (2), so re-executing accordingly with elevation."
                                                    #print "DEBUG: executing this:"
                                                    print "'"+sys.executable+" '"+os.path.abspath(__file__)+"''"
                                                    win32api.ShellExecute(0, "runas", sys.executable, '"'+os.path.abspath(__file__)+'"'+" --FLAG-SPRINGDS-INTERNAL-ELEVATION-LAUNCH", None, 1)
                                                    time.sleep(3)
                                                    wx.PostEvent(self.updatewin, TerminateWindowEvent(None))
                                                elif __file__:
                                                    print "[SpringDSPanel] Detected that we're in a EXE, so executing accordingly with elevation."
                                                    print "'"+__file__+" "+" '".join(sys.argv[1:])+"''"
                                                    win32api.ShellExecute(0, "runas", __file__, "' ".join(sys.argv[1:])+"' --FLAG-SPRINGDS-INTERNAL-ELEVATION-LAUNCH", None, 1)
                                                    time.sleep(3)
                                                    wx.PostEvent(self.updatewin, TerminateWindowEvent(None))
                                                else:
                                                    MsgBox("Failed to determine script execution environment!", "Error - SpringDS", wx.ICON_ERROR)
                                                    self.doKill()
                                                    #wx.PostEvent(self.updatewin, TerminateWindowEvent(None))
                                                    #print "[SpringDSPanel] Failed to determine script execution environment! Press ALT-F4 to exit."
                                                    
                                        except:
                                            MsgBox("Couldn't launch SpringDS in elevated mode!", "Error - SpringDS", wx.ICON_ERROR)
                                            self.doKill()
                                            #wx.PostEvent(self.updatewin, TerminateWindowEvent(None))
                                            #print "[SpringDSPanel] Couldn't launch SpringDS in elevated mode! Press ALT-F4 to exit."
                            else:
                                import traceback
                                if err.exception != "":
                                    wx.PostEvent(self.updatewin, ErrorNotifyEvent(err.exception+"\n\n"+"".join(traceback.format_exc())))
                                else:
                                    wx.PostEvent(self.updatewin, ErrorNotifyEvent("".join(traceback.format_exc())))
                                while self.errBoxOpen:
                                    time.sleep(1)
                                self.doKill()
                                #wx.PostEvent(self.updatewin, TerminateWindowEvent(None))
                                #print "[SpringDSPanel] Code failed! Press ALT-F4 to exit. [Inner loop]"
                                #wx.PostEvent(self.updatewin, UnhookOnQuitEvent(None))
                                raise
                        except SystemExit:
                            pass
                        except:
                            import traceback
                            print "GAHAHHHHHHHHH FAILURE!!!!"
                            traceback.print_exc()
                            wx.PostEvent(self.updatewin, ErrorNotifyEvent("".join(traceback.format_exc())))
                            while self.errBoxOpen:
                                time.sleep(1)
                            self.doKill()
                            #wx.PostEvent(self.updatewin, TerminateWindowEvent(None))
                            #print "[SpringDSPanel] Code failed! Press ALT-F4 to exit."
                            #wx.PostEvent(self.updatewin, UnhookOnQuitEvent(None))
                            raise
                    elif self.action == "ResetNetwork":
                        # Wrap all of this in a try/catch so that we can watch for errors and handle
                        # them nicely!
                        try:
                            wx.PostEvent(self.updatewin, UpdateProgressEvent(1))
                            self.initPyNM()
                            self.checkKill()
                            if self.checkActionDiff():
                                break
                            self.checkKill()
                            wx.PostEvent(self.updatewin, UpdateProgressEvent(50))
                            if SpringDSConfig.getCfgNICType() == 'wireless':
                                print "[SpringDSPanel] Resetting wireless NIC to DHCP..."
                                self.pyNMHandle.setWirelessDHCP()
                            elif SpringDSConfig.getCfgNICType() == 'lan':
                                print "[SpringDSPanel] Resetting LAN NIC to DHCP..."
                                self.pyNMHandle.setLANDHCP()
                            
                            self.checkKill()
                            wx.PostEvent(self.updatewin, UpdateProgressEvent(0))
                            print "[SpringDSPanel] Ready."
                        except pyNM.pyNMError, err:
                            # TODO: add more cases
                            # Is this a permission error?
                            if err.IsSystemError:
                                # Is this a permission error? (This is a subset of the system error)
                                if err.IsPermissionError:
                                    # Are we on Windows?
                                    if sys.platform == 'win32':
                                        wx.PostEvent(self.updatewin, UnhookOnQuitEvent(None))
                                        # Check args - this should be fixed later to actually check for elevation.
                                        ELEVATED = 0
                                        if len(sys.argv) > 1:
                                            if sys.argv[1] == '--FLAG-SPRINGDS-INTERNAL-ELEVATION-LAUNCH':
                                                # We tried elevating, it failed.
                                                ELEVATED = 1
                                                MsgBox("Could not set network config, even with elevation!", "Error - SpringDS", wx.ICON_ERROR)
                                                self.doKill()
                                                #wx.PostEvent(self.updatewin, TerminateWindowEvent(None))
                                                #print "[SpringDSPanel] Could not set network config, even with elevation. Press ALT-F4 to exit."
                                        try:
                                            if ELEVATED == 0:
                                                #print "DEBUG: sys.argv is "+str(sys.argv)
                                                #print "DEBUG: __file__ is "+str(__file__)
                                                if getattr(sys, 'frozen', False):
                                                    print "[SpringDSPanel] Detected regular old script execution, so re-executing accordingly with elevation."
                                                    #print "DEBUG: executing this:"
                                                    print "'"+sys.executable+" "+" ".join(sys.argv[1:])+"'"
                                                    win32api.ShellExecute(0, "runas", sys.executable, "'"+" ".join(sys.argv[1:])+"' --FLAG-SPRINGDS-INTERNAL-ELEVATION-LAUNCH", None, 1)
                                                    time.sleep(3)
                                                    wx.PostEvent(self.updatewin, TerminateWindowEvent(None))
                                                elif sys.argv[0][len(sys.argv[0])-3:] == '.py':
                                                    print "[SpringDSPanel] Detected regular old script execution (2), so re-executing accordingly with elevation."
                                                    #print "DEBUG: executing this:"
                                                    print "'"+sys.executable+" '"+os.path.abspath(__file__)+"''"
                                                    win32api.ShellExecute(0, "runas", sys.executable, '"'+os.path.abspath(__file__)+'"'+" --FLAG-SPRINGDS-INTERNAL-ELEVATION-LAUNCH", None, 1)
                                                    time.sleep(3)
                                                    wx.PostEvent(self.updatewin, TerminateWindowEvent(None))
                                                elif __file__:
                                                    print "[SpringDSPanel] Detected that we're in a EXE, so executing accordingly with elevation."
                                                    print "'"+__file__+" "+" '".join(sys.argv[1:])+"''"
                                                    win32api.ShellExecute(0, "runas", __file__, "' ".join(sys.argv[1:])+"' --FLAG-SPRINGDS-INTERNAL-ELEVATION-LAUNCH", None, 1)
                                                    time.sleep(3)
                                                    wx.PostEvent(self.updatewin, TerminateWindowEvent(None))
                                                else:
                                                    MsgBox("Failed to determine script execution environment!", "Error - SpringDS", wx.ICON_ERROR)
                                                    self.doKill()
                                                    #wx.PostEvent(self.updatewin, TerminateWindowEvent(None))
                                                    #print "[SpringDSPanel] Failed to determine script execution environment! Press ALT-F4 to exit."
                                                    
                                        except:
                                            MsgBox("Couldn't launch SpringDS in elevated mode!", "Error - SpringDS", wx.ICON_ERROR)
                                            self.doKill()
                                            #wx.PostEvent(self.updatewin, TerminateWindowEvent(None))
                                            #print "[SpringDSPanel] Couldn't launch SpringDS in elevated mode! Press ALT-F4 to exit."
                            else:
                                import traceback
                                if err.exception != "":
                                    wx.PostEvent(self.updatewin, ErrorNotifyEvent(err.exception+"\n\n"+"".join(traceback.format_exc())))
                                else:
                                    wx.PostEvent(self.updatewin, ErrorNotifyEvent("".join(traceback.format_exc())))
                                while self.errBoxOpen:
                                    time.sleep(1)
                                self.doKill()
                                #wx.PostEvent(self.updatewin, TerminateWindowEvent(None))
                                #print "[SpringDSPanel] Code failed! Press ALT-F4 to exit. [Inner loop]"
                                #wx.PostEvent(self.updatewin, UnhookOnQuitEvent(None))
                                raise
                        except SystemExit:
                            pass
                        except:
                            import traceback
                            print "GAHAHHHHHHHHH FAILURE!!!!"
                            traceback.print_exc()
                            wx.PostEvent(self.updatewin, ErrorNotifyEvent("".join(traceback.format_exc())))
                            while self.errBoxOpen:
                                time.sleep(1)
                            self.doKill()
                            #wx.PostEvent(self.updatewin, TerminateWindowEvent(None))
                            #print "[SpringDSPanel] Code failed! Press ALT-F4 to exit."
                            #wx.PostEvent(self.updatewin, UnhookOnQuitEvent(None))
                            raise
                    elif self.action == "":
                        # Do nothing
                        self.actionRan = True
                        print "[SpringDSPanel] Ready."
                        wx.PostEvent(self.updatewin, UpdateProgressEvent(0))
                    else:
                        import traceback
                        wx.PostEvent(self.updatewin, ErrorNotifyEvent("An invalid action has been specified. \n\n"+"".join(traceback.format_exc())))
                        while self.errBoxOpen:
                            time.sleep(1)
                        wx.PostEvent(self.updatewin, TerminateWindowEvent(None))
                        exit()
                    self.actionRan = True
                if self.checkActionDiff():
                    break
            self.actionRan = False

# begin wxGlade: extracode
# end wxGlade

class SpringDSPanelFrame(wx.Frame):
    def __init__(self, *args, **kwds):
        # begin wxGlade: SpringDSPanelFrame.__init__
        kwds["style"] = wx.CAPTION | wx.CLOSE_BOX | wx.MINIMIZE_BOX | wx.SYSTEM_MENU | wx.RESIZE_BORDER
        wx.Frame.__init__(self, *args, **kwds)
        self.SDSPBasePanel = wx.Panel(self, -1)
        self.SDSPHeaderImage = wx.StaticBitmap(self.SDSPBasePanel, -1, wx.Bitmap("SpringDSPanelHeader.png", wx.BITMAP_TYPE_ANY))
        self.SDSPProgressBar = wx.Gauge(self.SDSPBasePanel, -1, 10, style=wx.GA_HORIZONTAL | wx.GA_SMOOTH)
        self.SDSPStatusLbl = wx.StaticText(self.SDSPBasePanel, -1, "Ready.")
        self.SDSPButtonPanel = wx.Panel(self.SDSPBasePanel, -1)
        self.SDSPLaunchDSBtn = wx.Button(self.SDSPButtonPanel, -1, "Launch Driver Station")
        self.SDSPSetupNetworkBtn = wx.Button(self.SDSPButtonPanel, -1, "Setup Network")
        self.SDSPResetNetworkBtn = wx.Button(self.SDSPButtonPanel, -1, "Reset Network")
        self.SDSPExitBtn = wx.Button(self.SDSPButtonPanel, -1, "Exit")

        self.__set_properties()
        self.__do_layout()

        self.Bind(wx.EVT_BUTTON, self.OnLaunchDriverStation, self.SDSPLaunchDSBtn)
        self.Bind(wx.EVT_BUTTON, self.OnSetupNetwork, self.SDSPSetupNetworkBtn)
        self.Bind(wx.EVT_BUTTON, self.OnResetNetwork, self.SDSPResetNetworkBtn)
        self.Bind(wx.EVT_BUTTON, self.OnExit, self.SDSPExitBtn)
        # end wxGlade
        #self.Bind(wx.EVT_SIZE, self.on_size)
        
        # Background setup
        print "[SpringDS] Loading image from: "+os.path.join(os.getcwd(), "stripebg.png")
        self.bmp1 = wx.Bitmap(os.path.join(os.getcwd(), "stripebg.png"))
        
        self.SDSPButtonPanel.Bind(wx.EVT_PAINT, self.on_paint)
        self.Bind(wx.EVT_CLOSE, self.on_quit)
        
        # Connect the status update event to a callback
        EVT_UPDATE_STATUS(self, self.OnUpdateStatus)
        EVT_TERMINATE_WINDOW(self, self.OnTerminateWindow)
        EVT_UPDATE_PROGRESS(self, self.OnUpdateProgress)
        EVT_ERROR_NOTIFY(self, self.OnErrorNotify)
        EVT_RESET_LAUNCHER_BTN(self, self.OnResetLauncherBtn)
        
        self.SpringDS_NM_Slave_Instance = SpringDS_NM_Slave(self)
        self.SpringDS_NM_Slave_Instance.start()
        
        self.quitTriggered = False
        self.hasTerminated = False
    def __set_properties(self):
        # begin wxGlade: SpringDSPanelFrame.__set_properties
        self.SetTitle("SpringDS Panel")
        _icon = wx.EmptyIcon()
        _icon.CopyFromBitmap(wx.Bitmap("SpringDSPanelIcon.ico", wx.BITMAP_TYPE_ANY))
        self.SDSPProgressBar.SetRange(100)
        #self.SetIcon(_icon)
        self.SetIcon(wx.Icon("SpringDSPanelIcon.ico", wx.BITMAP_TYPE_ICO, 16, 16))
        # end wxGlade

    def __do_layout(self):
        # begin wxGlade: SpringDSPanelFrame.__do_layout
        SDSPBaseSizer = wx.BoxSizer(wx.VERTICAL)
        SDSPMainSizer = wx.FlexGridSizer(3, 1, 0, 0)
        SDSPButtonSizer = wx.FlexGridSizer(1, 4, 0, 0)
        SDSPIndicatorSizer = wx.FlexGridSizer(2, 1, 0, 0)
        SDSPMainSizer.Add(self.SDSPHeaderImage, 0, 0, 0)
        SDSPIndicatorSizer.Add(self.SDSPProgressBar, 0, wx.ALL | wx.EXPAND, 4)
        SDSPIndicatorSizer.Add(self.SDSPStatusLbl, 0, wx.ALL, 4)
        SDSPIndicatorSizer.AddGrowableRow(0)
        SDSPIndicatorSizer.AddGrowableRow(1)
        SDSPIndicatorSizer.AddGrowableCol(0)
        SDSPMainSizer.Add(SDSPIndicatorSizer, 1, wx.EXPAND, 0)
        SDSPButtonSizer.Add(self.SDSPLaunchDSBtn, 0, wx.ALL, 4)
        SDSPButtonSizer.Add(self.SDSPSetupNetworkBtn, 0, wx.ALL, 4)
        SDSPButtonSizer.Add(self.SDSPResetNetworkBtn, 0, wx.ALL, 4)
        SDSPButtonSizer.Add(self.SDSPExitBtn, 0, wx.ALL, 4)
        self.SDSPButtonPanel.SetSizer(SDSPButtonSizer)
        SDSPMainSizer.Add(self.SDSPButtonPanel, 1, wx.EXPAND, 0)
        self.SDSPBasePanel.SetSizer(SDSPMainSizer)
        SDSPMainSizer.AddGrowableCol(0)
        SDSPBaseSizer.Add(self.SDSPBasePanel, 1, wx.EXPAND, 0)
        self.SetSizer(SDSPBaseSizer)
        SDSPBaseSizer.Fit(self)
        self.Layout()
        self.Centre()
        # end wxGlade
    
    def OnLaunchDriverStation(self, event):  # wxGlade: SpringDSPanelFrame.<event_handler>
        if self.SDSPLaunchDSBtn.GetLabel() == "Launch Driver Station":
            self.SpringDS_NM_Slave_Instance.setAction("LaunchDS")
            self.SDSPLaunchDSBtn.SetLabel("Exit Driver Station")
        else:
            self.SpringDS_NM_Slave_Instance.setAction("TerminateDS")
            self.SDSPLaunchDSBtn.SetLabel("Launch Driver Station")
    def OnResetLauncherBtn(self, event):
        self.SDSPLaunchDSBtn.SetLabel("Launch Driver Station")
    def OnSetupNetwork(self, event):  # wxGlade: SpringDSPanelFrame.<event_handler>
        self.SpringDS_NM_Slave_Instance.setAction("SetupNetwork")
    
    def OnExit(self, event):  # wxGlade: SpringDSPanelFrame.<event_handler>
        self.Close()
    
    def OnResetNetwork(self, event):  # wxGlade: SpringDSPanelFrame.<event_handler>
        self.SpringDS_NM_Slave_Instance.setAction("ResetNetwork")
    
    def OnErrorNotify(self, event):
        # Show the error
        #print "CALLED: showing error!"
        ErrorBox('%s' % event.data)
        self.SpringDS_NM_Slave_Instance.setErrBoxClose()
        self.SetFocus()
    def OnUpdateProgress(self, event):
        self.SDSPProgressBar.SetValue(event.data)
    def OnTerminateWindow(self, event):
        self.hasTerminated = True
        self.SDSPStatusLbl.SetLabel("SpringDS has terminated, closing this window...")
        self.Refresh()
        self.Update()
        time.sleep(2)
        self.Destroy()
    def on_quit(self, event):
        self.SDSPLaunchDSBtn.Enable(False)
        self.SDSPSetupNetworkBtn.Enable(False)
        self.SDSPResetNetworkBtn.Enable(False)
        self.SDSPExitBtn.Enable(False)
        if (self.quitTriggered == False) and (self.hasTerminated == False):
            self.SDSPStatusLbl.SetLabel("Attempting to terminate SpringDS, please wait...")
            self.SpringDS_NM_Slave_Instance.killSlave()
            self.quitTriggered = True
            self.SDSPStatusLbl.SetLabel("SpringDS is terminating, please wait...")
            for proc in psutil.process_iter():
                if sys.platform == 'win32':
                    if proc.name == "Dashboard.exe":
                        proc.terminate()
                    if proc.name == "Driver Station.exe":
                        proc.terminate()
        else:
            self.SDSPStatusLbl.SetLabel("SpringDS is already terminating, please wait...")
    def OnUpdateStatus(self, event):
        # Update the status text!
        if event.data != None:
            # Process data and set the label
            self.SDSPStatusLbl.SetLabel('%s' % event.data)
    def on_paint(self, event):
        #print "[SpringDSPanel] [SpringDSFrame.on_paint] Function called for painting!"
        # Grab the source DC
        dc = wx.PaintDC(self.SDSPButtonPanel)
        
        # If something goes wrong... we still need something to draw on.
        if not dc:
            dc = wx.ClientDC(self.SDSPButtonPanel)
            rect = self.SDSPButtonPanel.GetUpdateRegion().GetBox()
            dc.SetClippingRect(rect) 
        
        w, h = dc.GetSize()
        # Get the BG image width and height!
        iw = self.bmp1.GetWidth()
        ih = self.bmp1.GetHeight()
        
        # Tile/wallpaper the image across the canvas
        for x in range(0, self.SDSPButtonPanel.GetSize()[0], iw):
            for y in range(0, self.SDSPButtonPanel.GetSize()[1], ih):
                dc.DrawBitmap(self.bmp1, x, y, True)
        

# end of class SpringDSPanelFrame
if __name__ == "__main__":
    print "SpringDS Panel v"+str(SPRINGDS_VERSION)
    bar = ""
    for i in range(0, len("SpringDS Panel v"+str(SPRINGDS_VERSION)) + 1):
        bar = bar + "="
    print bar
    print "Copyright (C) 2012 River Hill Robotics Team (Albert H.)\n"
    try:
        app = wx.PySimpleApp(0)
        wx.InitAllImageHandlers()
        SpringDSPanelFrameInstance = SpringDSPanelFrame(None, -1, "")
        app.SetTopWindow(SpringDSPanelFrameInstance)
        SpringDSPanelFrameInstance.Show()
        app.MainLoop()
    except:
        print "[SpringDSPanel] Crashed..."
        traceback.print_exc()
        ErrorBox("".join(traceback.format_exc()))
